/*
 /**
*** Project Name: LabSage
*** Date: 20 Feb 2023
*** Version: V1.0.8 - WiFi - dynamic selection debugged
*

//  LIBRARIES
//FirebaseESP8266.h must be included before ESP8266WiFi.h

#include <FirebaseESP8266.h>  // Install Firebase ESP8266 library (Mobitz?)
#include <MB_NTP.h>
#include <ESP8266WiFi.h>
#include <DHT.h>              // Install DHT11 Library and Adafruit Unified Sensor Library
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>   // Install Adafruit ADXL345 accelerometer library
#include <WiFiManager.h>

#define FIREBASE_HOST "https://smartlab-9b83e-default-rtdb.firebaseio.com/"
#define FIREBASE_AUTH "AIzaSyCiO5owTmUgosDyjL0_SqpxRoAwgKtn5-o"

//  modify the foll according to the Wi-Fi name and login in the van
//#define WIFI_SSID "SMI_2G"              //"TP-Link_5916"
//#define WIFI_PASSWORD "SMI@12345"       //"76927164"

#define DHTPIN D2        // Connect Data pin of DHT to D2
#define GASPIN A0        // Gas sensor analog pin
#define BUZZERPIN D7     // Connect LED to D7
#define SDA D5
#define SCL D6
#define LED D1

#define DHTTYPE    DHT11
DHT dht(DHTPIN, DHTTYPE);

WiFiManager wm;

//Define FirebaseESP8266 data object
FirebaseData firebaseData;
FirebaseData buzzerData;
FirebaseData collisionData;

FirebaseJson json;

//MQ2 parameter for CO Gas sensing
float gasSensor_volt;
float RS;
const float R0 = 2.12;
const float b = 1.5120222;
const float m = -0.33975668;
float RS_R0_ratio;
float ppm_log;
float ppm;
float t,h,g;
String buzz = "0";
String coll = "0";
String UID = "";
String PATH = "Devices/";
//Time delay  = (SAMPLES * INTERVAL)
#define SAMPLES 10//600
#define INTERVAL 10

float x, y, z;

/* Create an instance of the ADXL345 class *
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);

/* Threshold for detecting a collision *
const float COLLISION_THRESHOLD = 15.0;

float SMOKE_THRESHOLD = 1000;
// Function Declaration

void dhtSetup(void);
void gasSetup(void);
void ambiRead(void);
void accelSetup(void);
void accelRead(void);
void sensorUpdate(void);
void sensorReset(void);
void upload(void);
void displaySensorDetails(void);
void displayDataRate(void);
void displayRange(void);

void setup()
{
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);
  pinMode(BUZZERPIN, OUTPUT);
  Serial.begin(9600);
  dhtSetup();
  gasSetup();
  accelSetup();
//  wm.erase();             // Remove before deployment
  
  Serial.println("Opening WiFi AP");
  bool res;
  res = wm.autoConnect(); // auto generated AP name from chipid
    if(!res) {
        Serial.println("Failed to connect");
        // ESP.restart();
    } 
    else {
        //if you get here you have connected to the WiFi    
        Serial.println("Connected");
    }
  wm.setWiFiAutoReconnect(true);
  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
  Firebase.reconnectWiFi(true);
  UID = ESP.getChipId();
  Serial.printf("ESP8266 Unique Chip id = %s\n", UID);    // %08X
  Serial.println();
  Serial.println(PATH.concat(UID));

    //configure receiver callback
  // Indication that system is ready for use
  tone(BUZZERPIN, 250);
    delay(300);
  noTone(BUZZERPIN);
  delay(300);
  tone(BUZZERPIN, 250);
    delay(300);
  noTone(BUZZERPIN);
  delay(300);
  tone(BUZZERPIN, 250);
    delay(300);
  noTone(BUZZERPIN);
  //delay(300);
  digitalWrite(LED, HIGH);
}

void loop() {
  if(WiFi.status() == WL_CONNECTED){
//  char rst = Serial.read();
   if(Firebase.getString(buzzerData, PATH+"/reset") && buzzerData.stringData() == "1"){                    //Read from firebase for application
    Serial.println("Call to reset");
    sensorReset();
 if (Firebase.setString(firebaseData, PATH+"/buzzer", buzz))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
  if (Firebase.setString(firebaseData, PATH+"/collision", coll))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
    if (Firebase.setString(firebaseData, PATH+"/reset", "0"))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
  }
  sensorUpdate();
  upload();
  digitalWrite(LED, HIGH);
  }
  else{
    digitalWrite(LED, !digitalRead(LED));
  }
 // delay(500);
}


void accelSetup(void) {
  Serial.println("Accelerometer Test"); Serial.println("");

  // Initialise I2C communication as MASTER
  Wire.begin(SDA, SCL);

  if(!accel.begin()) {
    Serial.println("Failed to initialize ADXL345 sensor.");
    while(1);
  }
  accel.setRange(ADXL345_RANGE_16_G);
  /* Get accelerometer data *
  sensors_event_t event;
  accel.getEvent(&event);
//  Assign current values to states
  x = event.acceleration.x;
  y = event.acceleration.y;
  z = event.acceleration.z;
  Serial.println("Accelerometer Ready!"); Serial.println("");
  displaySensorDetails();
  displayDataRate();
  displayRange();
}

void accelRead(void){
  /* Get accelerometer data *
  sensors_event_t event;
  accel.getEvent(&event);
  
  /* Print the accelerometer data to serial monitor *
  Serial.print("Acceleration: ");
  Serial.print(event.acceleration.x);
  Serial.print(" m/s^2 ");
  Serial.print(event.acceleration.y);
  Serial.print(" m/s^2 ");
  Serial.print(event.acceleration.z);
  Serial.println(" m/s^2 ");
  if (isnan(event.acceleration.x) || isnan(event.acceleration.y) || isnan(event.acceleration.z)) {
    Serial.println(F("Failed to read from Accelerometer!"));
    return;
  }
  /* Check if there is a collision *
  if((abs(event.acceleration.x - x)) > COLLISION_THRESHOLD ||
     (abs(event.acceleration.y - y)) > COLLISION_THRESHOLD ||
     (abs(event.acceleration.z - z)) > COLLISION_THRESHOLD) {
    Serial.println("Collision detected!");
    coll = "1";
    tone(BUZZERPIN, 100);
   }
//   else{
//    coll="0";
//   }
//  Assign current values to states
  x = event.acceleration.x;
  y = event.acceleration.y;
  z = event.acceleration.z;
}

void dhtSetup(void) {
  Serial.println(F("DHT11 setting up..."));
  dht.begin();
  Serial.println("DHT11 ready!");
}

void gasSetup(void) {
  Serial.println("Gas Sensor setting up...");
  pinMode(GASPIN, INPUT);
  int cnt = 3;
  float temp = 0;
 while(cnt!=0){
  float gasSensorValue = analogRead(GASPIN);
    gasSensor_volt = gasSensorValue / 1024 * 5.0;
    RS = ((5 - gasSensor_volt) / gasSensor_volt);
    RS_R0_ratio = RS / R0;
    ppm_log = ((log (RS_R0_ratio) - b) / m);
    ppm = pow (10, ppm_log);
    temp = temp+ppm;
    cnt--;
    delay(1000);
 }
 SMOKE_THRESHOLD = SMOKE_THRESHOLD+(temp/3);
    Serial.println("Gas Sensor ready!");
    Serial.printf("\nSmoke Threshold: %f ppm\n", SMOKE_THRESHOLD);
  Serial.println("");
}

void ambiRead(void){

    // Read relative humidity in % (the default)
    h = dht.readHumidity();

 // Read temperature as Celsius (the default)
    t = dht.readTemperature();
 // Read gas sensor analog data
    float gasSensorValue = analogRead(GASPIN);
    gasSensor_volt = gasSensorValue / 1024 * 5.0;
    RS = ((5 - gasSensor_volt) / gasSensor_volt);
    RS_R0_ratio = RS / R0;
    ppm_log = ((log (RS_R0_ratio) - b) / m);
    ppm = pow (10, ppm_log);
    g = ppm;

 // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t) || isnan(g)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }
  
    Serial.print(F("Humidity: "));
    Serial.print(h);
    Serial.print(F("%  Temperature: "));
    Serial.print(t);
    Serial.print(F("C  PPM: "));
    Serial.print(g);
    Serial.println();
    /* Check if there is a fire *
  if(g > SMOKE_THRESHOLD) {
    Serial.println("Smoke detected!");
    buzz="1";
    tone(BUZZERPIN, 400);
   }
   else{
    buzz="0";
   if(coll == "0"){ noTone(BUZZERPIN);}
   }
}

void sensorUpdate(void) {
    ambiRead();  
    accelRead();
    
    delay(500);
}

void sensorReset(void){
    coll="0";
    buzz="0";
}

void upload(void){
  if (Firebase.setFloat(firebaseData, PATH+"/temperature", t))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }

  if (Firebase.setFloat(firebaseData, PATH+"/humidity", h))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
  if (Firebase.setFloat(firebaseData, PATH+"/ppm", g))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }

    if (Firebase.setString(firebaseData, PATH+"/buzzer", buzz))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }

  if (Firebase.setFloat(firebaseData, PATH+"/x", x))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
  if (Firebase.setFloat(firebaseData, PATH+"/y", y))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
  if (Firebase.setFloat(firebaseData, PATH+"/z", z))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
   if (Firebase.setString(firebaseData, PATH+"/collision", coll))
  {
    Serial.println("PASSED");
    Serial.println("PATH: " + firebaseData.dataPath());
    Serial.println("TYPE: " + firebaseData.dataType());
    Serial.println("ETag: " + firebaseData.ETag());
    Serial.println("------------------------------------");
    Serial.println();
  }
  else
  {
    Serial.println("FAILED");
    Serial.println("REASON: " + firebaseData.errorReason());
    Serial.println("------------------------------------");
    Serial.println();
  }
}
void displaySensorDetails(void)
  {
  sensor_t sensor;
  accel.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print ("Sensor: "); Serial.println(sensor.name);
  Serial.print ("Driver Ver: "); Serial.println(sensor.version);
  Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
  Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" m/s^2");
  Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" m/s^2");
  Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" m/s^2");
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
  }

  void displayDataRate(void)
  {
  Serial.print ("Data Rate: ");

  switch (accel.getDataRate())
  {
    case ADXL345_DATARATE_3200_HZ:
      Serial.print ("3200 ");
      break;
    case ADXL345_DATARATE_1600_HZ:
      Serial.print ("1600 ");
      break;
    case ADXL345_DATARATE_800_HZ:
      Serial.print ("800 ");
      break;
    case ADXL345_DATARATE_400_HZ:
      Serial.print ("400 ");
      break;
    case ADXL345_DATARATE_200_HZ:
      Serial.print ("200 ");
      break;
    case ADXL345_DATARATE_100_HZ:
      Serial.print ("100 ");
      break;
    case ADXL345_DATARATE_50_HZ:
      Serial.print ("50 ");
      break;
    case ADXL345_DATARATE_25_HZ:
      Serial.print ("25 ");
      break;
    case ADXL345_DATARATE_12_5_HZ:
      Serial.print ("12.5 ");
      break;
    case ADXL345_DATARATE_6_25HZ:
      Serial.print ("6.25 ");
      break;
    case ADXL345_DATARATE_3_13_HZ:
      Serial.print ("3.13 ");
      break;
    case ADXL345_DATARATE_1_56_HZ:
      Serial.print ("1.56 ");
      break;
    case ADXL345_DATARATE_0_78_HZ:
      Serial.print ("0.78 ");
      break;
    case ADXL345_DATARATE_0_39_HZ:
      Serial.print ("0.39 ");
      break;
    case ADXL345_DATARATE_0_20_HZ:
      Serial.print ("0.20 ");
      break;
    case ADXL345_DATARATE_0_10_HZ:
      Serial.print ("0.10 ");
      break;
    default:
      Serial.print ("???? ");
      break;
  }
  Serial.println(" Hz");
  }

  void displayRange(void)
  {
  Serial.print ("Range: +/- ");

  switch (accel.getRange())
  {
    case ADXL345_RANGE_16_G:
      Serial.print ("16 ");
      break;
    case ADXL345_RANGE_8_G:
      Serial.print ("8 ");
      break;
    case ADXL345_RANGE_4_G:
      Serial.print ("4 ");
      break;
    case ADXL345_RANGE_2_G:
      Serial.print ("2 ");
      break;
    default:
      Serial.print ("?? ");
      break;
  }
  Serial.println(" g");
  }
 * */
